#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DMX512控制系统主界面
基于PyQt5的专业灯光控制系统
"""

import sys
import os
import json
from typing import Dict, List, Optional, Tuple
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import numpy as np

from dmx_core import (
    DMXController, SerialDMXInterface, SimulatedDMXInterface,
    RGBLight, RGBWLight, MovingHead, DMXDevice
)
from rs485_dmx import (
    RS485DMXInterface, RS485ProtocolType, RS485DeviceType, 
    RS485Device, get_available_rs485_ports
)


class ColorPickerWidget(QWidget):
    """颜色选择器组件"""
    
    colorChanged = pyqtSignal(int, int, int)  # RGB值变化信号
    
    def __init__(self):
        super().__init__()
        self.init_ui()
        
    def init_ui(self):
        layout = QVBoxLayout()
        
        # 颜色显示区域
        self.color_display = QLabel("🎨 当前颜色")
        self.color_display.setFixedSize(180, 60)
        self.color_display.setAlignment(Qt.AlignCenter)
        self.color_display.setStyleSheet("""
            QLabel {
                border: 2px solid #00d4aa;
                border-radius: 8px;
                background-color: #000000;
                color: white;
                font-weight: bold;
            }
        """)
        layout.addWidget(self.color_display)
        
        # RGB滑块
        self.rgb_sliders = {}
        for color, name in [('R', '红色'), ('G', '绿色'), ('B', '蓝色')]:
            group = QGroupBox(f"{name} ({color})")
            group_layout = QHBoxLayout()
            
            slider = QSlider(Qt.Horizontal)
            slider.setRange(0, 255)
            slider.setValue(0)
            slider.valueChanged.connect(self.update_color)
            
            spinbox = QSpinBox()
            spinbox.setRange(0, 255)
            spinbox.setValue(0)
            spinbox.valueChanged.connect(lambda v, s=slider: s.setValue(v))
            slider.valueChanged.connect(lambda v, s=spinbox: s.setValue(v))
            
            group_layout.addWidget(slider)
            group_layout.addWidget(spinbox)
            group.setLayout(group_layout)
            
            self.rgb_sliders[color.lower()] = slider
            layout.addWidget(group)
        
        # 预设颜色按钮
        preset_layout = QGridLayout()
        preset_colors = [
            ("红色", (255, 0, 0)),
            ("绿色", (0, 255, 0)),
            ("蓝色", (0, 0, 255)),
            ("黄色", (255, 255, 0)),
            ("青色", (0, 255, 255)),
            ("品红", (255, 0, 255)),
            ("白色", (255, 255, 255)),
            ("橙色", (255, 165, 0))
        ]
        
        for i, (name, (r, g, b)) in enumerate(preset_colors):
            btn = QPushButton(name)
            btn.setFixedSize(60, 30)
            btn.setStyleSheet(f"background-color: rgb({r},{g},{b}); color: white; font-weight: bold;")
            btn.clicked.connect(lambda checked, rgb=(r,g,b): self.set_color(*rgb))
            preset_layout.addWidget(btn, i // 4, i % 4)
        
        layout.addLayout(preset_layout)
        
        # 颜色选择对话框按钮
        color_dialog_btn = QPushButton("打开颜色选择器")
        color_dialog_btn.clicked.connect(self.open_color_dialog)
        layout.addWidget(color_dialog_btn)
        
        self.setLayout(layout)
        
    def update_color(self):
        """更新颜色显示"""
        r = self.rgb_sliders['r'].value()
        g = self.rgb_sliders['g'].value()
        b = self.rgb_sliders['b'].value()
        
        self.color_display.setStyleSheet(f"""
            QLabel {{
                border: 2px solid #00d4aa;
                border-radius: 8px;
                background-color: rgb({r},{g},{b});
                color: white;
                font-weight: bold;
            }}
        """)
        self.colorChanged.emit(r, g, b)
        
    def set_color(self, r: int, g: int, b: int):
        """设置颜色值"""
        self.rgb_sliders['r'].setValue(r)
        self.rgb_sliders['g'].setValue(g)
        self.rgb_sliders['b'].setValue(b)
        
    def get_color(self) -> Tuple[int, int, int]:
        """获取当前颜色值"""
        return (
            self.rgb_sliders['r'].value(),
            self.rgb_sliders['g'].value(),
            self.rgb_sliders['b'].value()
        )
        
    def open_color_dialog(self):
        """打开系统颜色选择对话框"""
        color = QColorDialog.getColor(Qt.white, self)
        if color.isValid():
            self.set_color(color.red(), color.green(), color.blue())


class ChannelFaderWidget(QWidget):
    """通道推子组件"""
    
    valueChanged = pyqtSignal(int, int)  # 通道号, 值
    
    def __init__(self, channel: int, name: str = ""):
        super().__init__()
        self.channel = channel
        self.init_ui(name or f"CH {channel}")
        
    def init_ui(self, name: str):
        layout = QVBoxLayout()
        layout.setSpacing(5)
        
        # 通道名称
        name_label = QLabel(name)
        name_label.setAlignment(Qt.AlignCenter)
        name_label.setStyleSheet("font-weight: bold; color: #333;")
        layout.addWidget(name_label)
        
        # 数值显示
        self.value_label = QLabel("0")
        self.value_label.setAlignment(Qt.AlignCenter)
        self.value_label.setStyleSheet("color: #007acc; font-size: 14px; font-weight: bold;")
        layout.addWidget(self.value_label)
        
        # 垂直滑块
        self.slider = QSlider(Qt.Vertical)
        self.slider.setRange(0, 255)
        self.slider.setValue(0)
        self.slider.setFixedWidth(30)
        self.slider.setFixedHeight(150)
        self.slider.valueChanged.connect(self.on_value_changed)
        layout.addWidget(self.slider, alignment=Qt.AlignCenter)
        
        # 输入框
        self.spinbox = QSpinBox()
        self.spinbox.setRange(0, 255)
        self.spinbox.setValue(0)
        self.spinbox.setFixedWidth(60)
        self.spinbox.valueChanged.connect(self.slider.setValue)
        layout.addWidget(self.spinbox, alignment=Qt.AlignCenter)
        
        # 快捷按钮
        button_layout = QHBoxLayout()
        
        zero_btn = QPushButton("0")
        zero_btn.setFixedSize(25, 25)
        zero_btn.clicked.connect(lambda: self.set_value(0))
        
        full_btn = QPushButton("F")
        full_btn.setFixedSize(25, 25)
        full_btn.clicked.connect(lambda: self.set_value(255))
        
        button_layout.addWidget(zero_btn)
        button_layout.addWidget(full_btn)
        layout.addLayout(button_layout)
        
        self.setLayout(layout)
        self.setFixedWidth(80)
        
    def on_value_changed(self, value: int):
        """值变化处理"""
        self.value_label.setText(str(value))
        self.spinbox.setValue(value)
        self.valueChanged.emit(self.channel, value)
        
    def set_value(self, value: int):
        """设置通道值"""
        self.slider.setValue(value)
        
    def get_value(self) -> int:
        """获取通道值"""
        return self.slider.value()


class DeviceWidget(QWidget):
    """设备控制组件"""
    
    def __init__(self, device: DMXDevice, controller: DMXController):
        super().__init__()
        self.device = device
        self.controller = controller
        self.init_ui()
        
    def init_ui(self):
        layout = QVBoxLayout()
        layout.setSpacing(10)
        layout.setContentsMargins(10, 10, 10, 10)
        
        # 设备信息标题 - 简化布局
        info_layout = QHBoxLayout()
        
        # 根据设备类型选择图标
        if isinstance(self.device, RGBLight):
            icon = "🔴"
        elif isinstance(self.device, RGBWLight):
            icon = "🌈"
        elif isinstance(self.device, MovingHead):
            icon = "🎯"
        else:
            icon = "💡"
            
        name_label = QLabel(f"{icon} {self.device.name}")
        name_label.setStyleSheet("""
            QLabel {
                font-weight: bold; 
                font-size: 16px; 
                color: #00d4aa;
                padding: 5px;
            }
        """)
        
        channel_label = QLabel(f"通道: {self.device.start_channel}-{self.device.start_channel + self.device.channel_count - 1}")
        channel_label.setStyleSheet("""
            QLabel {
                color: #7f8c8d; 
                font-size: 12px;
                background: rgba(0, 212, 170, 0.1);
                border-radius: 4px;
                padding: 4px 8px;
            }
        """)
        
        info_layout.addWidget(name_label)
        info_layout.addStretch()
        info_layout.addWidget(channel_label)
        layout.addLayout(info_layout)
        
        # 根据设备类型创建控制界面
        if isinstance(self.device, (RGBLight, RGBWLight)):
            self.create_rgb_controls(layout)
        elif isinstance(self.device, MovingHead):
            self.create_moving_head_controls(layout)
        else:
            self.create_generic_controls(layout)
            
        self.setLayout(layout)
        
        # 设置设备框样式
        self.setMinimumWidth(300)  # 只设置最小宽度
        self.setStyleSheet("""
            DeviceWidget {
                border: 2px solid #00d4aa;
                border-radius: 10px;
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 rgba(0, 212, 170, 0.1), stop:1 rgba(0, 212, 170, 0.05));
                margin: 5px;
                padding: 10px;
            }
        """)
        
    def create_rgb_controls(self, layout: QVBoxLayout):
        """创建RGB设备控制"""
        # 颜色选择器
        self.color_picker = ColorPickerWidget()
        self.color_picker.colorChanged.connect(self.on_color_changed)
        layout.addWidget(self.color_picker)
        
        # 如果是RGBW设备，添加白光控制
        if isinstance(self.device, RGBWLight):
            white_group = QGroupBox("白光")
            white_layout = QHBoxLayout()
            
            self.white_slider = QSlider(Qt.Horizontal)
            self.white_slider.setRange(0, 255)
            self.white_slider.valueChanged.connect(self.on_white_changed)
            
            white_spinbox = QSpinBox()
            white_spinbox.setRange(0, 255)
            white_spinbox.valueChanged.connect(self.white_slider.setValue)
            self.white_slider.valueChanged.connect(white_spinbox.setValue)
            
            white_layout.addWidget(self.white_slider)
            white_layout.addWidget(white_spinbox)
            white_group.setLayout(white_layout)
            layout.addWidget(white_group)
            
    def create_moving_head_controls(self, layout: QVBoxLayout):
        """创建摇头灯控制"""
        # 位置控制
        pos_group = QGroupBox("位置控制")
        pos_layout = QGridLayout()
        
        # Pan控制
        pos_layout.addWidget(QLabel("水平 (Pan):"), 0, 0)
        self.pan_slider = QSlider(Qt.Horizontal)
        self.pan_slider.setRange(0, 255)
        self.pan_slider.valueChanged.connect(self.on_position_changed)
        pos_layout.addWidget(self.pan_slider, 0, 1)
        
        pan_spinbox = QSpinBox()
        pan_spinbox.setRange(0, 255)
        pan_spinbox.valueChanged.connect(self.pan_slider.setValue)
        self.pan_slider.valueChanged.connect(pan_spinbox.setValue)
        pos_layout.addWidget(pan_spinbox, 0, 2)
        
        # Tilt控制
        pos_layout.addWidget(QLabel("垂直 (Tilt):"), 1, 0)
        self.tilt_slider = QSlider(Qt.Horizontal)
        self.tilt_slider.setRange(0, 255)
        self.tilt_slider.valueChanged.connect(self.on_position_changed)
        pos_layout.addWidget(self.tilt_slider, 1, 1)
        
        tilt_spinbox = QSpinBox()
        tilt_spinbox.setRange(0, 255)
        tilt_spinbox.valueChanged.connect(self.tilt_slider.setValue)
        self.tilt_slider.valueChanged.connect(tilt_spinbox.setValue)
        pos_layout.addWidget(tilt_spinbox, 1, 2)
        
        pos_group.setLayout(pos_layout)
        layout.addWidget(pos_group)
        
        # 亮度控制
        dimmer_group = QGroupBox("亮度控制")
        dimmer_layout = QHBoxLayout()
        
        self.dimmer_slider = QSlider(Qt.Horizontal)
        self.dimmer_slider.setRange(0, 255)
        self.dimmer_slider.valueChanged.connect(self.on_dimmer_changed)
        
        dimmer_spinbox = QSpinBox()
        dimmer_spinbox.setRange(0, 255)
        dimmer_spinbox.valueChanged.connect(self.dimmer_slider.setValue)
        self.dimmer_slider.valueChanged.connect(dimmer_spinbox.setValue)
        
        dimmer_layout.addWidget(self.dimmer_slider)
        dimmer_layout.addWidget(dimmer_spinbox)
        dimmer_group.setLayout(dimmer_layout)
        layout.addWidget(dimmer_group)
        
        # 颜色控制
        self.color_picker = ColorPickerWidget()
        self.color_picker.colorChanged.connect(self.on_color_changed)
        layout.addWidget(self.color_picker)
        
    def create_generic_controls(self, layout: QVBoxLayout):
        """创建通用设备控制"""
        channels_layout = QHBoxLayout()
        self.channel_faders = []
        
        for i in range(min(self.device.channel_count, 8)):  # 最多显示8个通道
            channel = self.device.start_channel + i
            fader = ChannelFaderWidget(channel, f"CH{i+1}")
            fader.valueChanged.connect(self.on_channel_changed)
            self.channel_faders.append(fader)
            channels_layout.addWidget(fader)
            
        layout.addLayout(channels_layout)
        
    def on_color_changed(self, r: int, g: int, b: int):
        """颜色变化处理"""
        if isinstance(self.device, RGBLight):
            self.device.set_color(self.controller, r, g, b)
        elif isinstance(self.device, RGBWLight):
            w = getattr(self, 'white_slider', QSlider()).value()
            self.device.set_color(self.controller, r, g, b, w)
        elif isinstance(self.device, MovingHead):
            self.device.set_color(self.controller, r, g, b)
            
    def on_white_changed(self, w: int):
        """白光变化处理"""
        if isinstance(self.device, RGBWLight):
            r, g, b = self.color_picker.get_color()
            self.device.set_color(self.controller, r, g, b, w)
            
    def on_position_changed(self):
        """位置变化处理"""
        if isinstance(self.device, MovingHead):
            pan = self.pan_slider.value()
            tilt = self.tilt_slider.value()
            self.device.set_position(self.controller, pan, tilt)
            
    def on_dimmer_changed(self, value: int):
        """亮度变化处理"""
        if isinstance(self.device, MovingHead):
            self.controller.set_channel(self.device.start_channel + 4, value)  # Dimmer通道
            
    def on_channel_changed(self, channel: int, value: int):
        """通道值变化处理"""
        self.controller.set_channel(channel, value)


class DMXControllerGUI(QMainWindow):
    """DMX控制器主界面"""
    
    def __init__(self):
        super().__init__()
        self.controller = DMXController()
        self.devices = []
        self.scenes = {}
        self.init_ui()
        self.show_splash_screen()
        self.init_dmx()
        
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("DMX512 专业灯光控制系统")
        self.setGeometry(100, 100, 1600, 1000)
        self.setMinimumSize(1200, 800)
        self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
        
        # 创建中央窗口部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(10)
        main_layout.setContentsMargins(10, 10, 10, 10)
        
        # 上方内容区域
        content_layout = QHBoxLayout()
        content_layout.setSpacing(15)
        
        # 左侧面板
        left_panel = self.create_left_panel()
        left_panel.setMaximumWidth(350)
        left_panel.setMinimumWidth(320)
        content_layout.addWidget(left_panel)
        
        # 右侧面板
        right_panel = self.create_right_panel()
        content_layout.addWidget(right_panel, 1)
        
        main_layout.addLayout(content_layout, 3)
        
        # 底部通道监控面板
        bottom_panel = self.create_bottom_panel()
        bottom_panel.setMaximumHeight(200)
        main_layout.addWidget(bottom_panel, 1)
        
        # 创建菜单栏
        self.create_menu_bar()
        
        # 创建状态栏
        self.create_status_bar()
        
        # 应用样式
        self.apply_styles()
        
    def show_splash_screen(self):
        """显示炫酷的启动屏幕"""
        splash_pixmap = QPixmap(400, 300)
        splash_pixmap.fill(QColor(26, 26, 46))
        
        painter = QPainter(splash_pixmap)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # 绘制背景渐变
        gradient = QLinearGradient(0, 0, 400, 300)
        gradient.setColorAt(0, QColor(26, 26, 46))
        gradient.setColorAt(0.5, QColor(22, 33, 62))
        gradient.setColorAt(1, QColor(15, 52, 96))
        painter.fillRect(0, 0, 400, 300, QBrush(gradient))
        
        # 绘制标题
        painter.setPen(QColor(0, 212, 170))
        font = QFont("Microsoft YaHei", 24, QFont.Bold)
        painter.setFont(font)
        painter.drawText(50, 100, "DMX512")
        
        painter.setPen(QColor(255, 255, 255))
        font = QFont("Microsoft YaHei", 16)
        painter.setFont(font)
        painter.drawText(50, 130, "专业灯光控制系统")
        
        # 绘制版本信息
        painter.setPen(QColor(127, 140, 141))
        font = QFont("Microsoft YaHei", 12)
        painter.setFont(font)
        painter.drawText(50, 200, "版本 1.0")
        painter.drawText(50, 220, "正在初始化...")
        
        # 绘制装饰性的圆点
        painter.setPen(QPen(QColor(0, 212, 170), 2))
        for i in range(5):
            x = 300 + i * 15
            y = 250
            painter.drawEllipse(x, y, 8, 8)
            
        painter.end()
        
        self.splash = QSplashScreen(splash_pixmap)
        self.splash.show()
        
        # 使用定时器自动关闭启动屏幕
        QTimer.singleShot(2000, self.splash.close)
        
    def create_left_panel(self) -> QWidget:
        """创建左侧控制面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # DMX接口设置
        interface_group = QGroupBox("DMX接口设置")
        interface_layout = QVBoxLayout()
        
        # 接口类型选择
        self.interface_combo = QComboBox()
        self.interface_combo.addItem("🎭 模拟接口", "simulator")
        
        # 添加可用串口
        ports = self.controller.get_available_ports()
        for port in ports:
            self.interface_combo.addItem(f"📡 串口DMX: {port}", f"serial:{port}")
        
        # 添加RS485端口
        rs485_ports = get_available_rs485_ports()
        for port, description in rs485_ports:
            self.interface_combo.addItem(f"🔗 RS485: {description}", f"rs485:{port}")
            
        interface_layout.addWidget(QLabel("接口类型:"))
        interface_layout.addWidget(self.interface_combo)
        
        # 连接按钮
        self.connect_btn = QPushButton("连接")
        self.connect_btn.clicked.connect(self.connect_dmx)
        interface_layout.addWidget(self.connect_btn)
        
        # 连接状态指示
        self.status_indicator = QLabel("未连接")
        self.status_indicator.setStyleSheet("color: red; font-weight: bold;")
        interface_layout.addWidget(self.status_indicator)
        
        interface_group.setLayout(interface_layout)
        layout.addWidget(interface_group)
        
        # 主控制器
        master_group = QGroupBox("主控制")
        master_layout = QVBoxLayout()
        
        # 主亮度控制
        self.master_dimmer = QSlider(Qt.Horizontal)
        self.master_dimmer.setRange(0, 100)
        self.master_dimmer.setValue(100)
        self.master_dimmer.valueChanged.connect(self.on_master_dimmer_changed)
        
        master_layout.addWidget(QLabel("主亮度:"))
        master_layout.addWidget(self.master_dimmer)
        
        self.master_value_label = QLabel("100%")
        self.master_value_label.setAlignment(Qt.AlignCenter)
        master_layout.addWidget(self.master_value_label)
        
        # 快捷按钮
        button_layout = QGridLayout()
        
        blackout_btn = QPushButton("🌑 全部熄灭")
        blackout_btn.setObjectName("danger")
        blackout_btn.clicked.connect(self.blackout_all)
        button_layout.addWidget(blackout_btn, 0, 0)
        
        full_on_btn = QPushButton("☀️ 全部点亮")
        full_on_btn.setObjectName("warning")
        full_on_btn.clicked.connect(self.full_on_all)
        button_layout.addWidget(full_on_btn, 0, 1)
        
        test_btn = QPushButton("🔧 通道测试")
        test_btn.clicked.connect(self.test_channels)
        button_layout.addWidget(test_btn, 1, 0, 1, 2)
        
        master_layout.addLayout(button_layout)
        master_group.setLayout(master_layout)
        layout.addWidget(master_group)
        
        # 场景控制
        scene_group = QGroupBox("场景控制")
        scene_layout = QVBoxLayout()
        
        self.scene_list = QListWidget()
        self.scene_list.itemDoubleClicked.connect(self.load_scene)
        scene_layout.addWidget(self.scene_list)
        
        scene_button_layout = QHBoxLayout()
        
        save_scene_btn = QPushButton("保存场景")
        save_scene_btn.clicked.connect(self.save_scene)
        scene_button_layout.addWidget(save_scene_btn)
        
        delete_scene_btn = QPushButton("删除场景")
        delete_scene_btn.clicked.connect(self.delete_scene)
        scene_button_layout.addWidget(delete_scene_btn)
        
        scene_layout.addLayout(scene_button_layout)
        scene_group.setLayout(scene_layout)
        layout.addWidget(scene_group)
        
        layout.addStretch()
        return panel
        
    def create_right_panel(self) -> QWidget:
        """创建右侧设备控制面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # 工具栏
        toolbar_layout = QHBoxLayout()
        
        add_device_btn = QPushButton("添加设备")
        add_device_btn.clicked.connect(self.add_device)
        toolbar_layout.addWidget(add_device_btn)
        
        remove_device_btn = QPushButton("删除设备")
        remove_device_btn.clicked.connect(self.remove_device)
        toolbar_layout.addWidget(remove_device_btn)
        
        toolbar_layout.addStretch()
        
        layout.addLayout(toolbar_layout)
        
        # 设备控制区域
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        
        self.device_container = QWidget()
        self.device_layout = QVBoxLayout(self.device_container)
        self.device_layout.setAlignment(Qt.AlignTop)
        self.device_layout.setSpacing(10)
        
        scroll_area.setWidget(self.device_container)
        layout.addWidget(scroll_area)
        
        return panel
        
    def create_bottom_panel(self) -> QWidget:
        """创建底部通道监控面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # 标题
        title_layout = QHBoxLayout()
        title_label = QLabel("📊 实时通道监控")
        title_label.setStyleSheet("""
            QLabel {
                font-size: 16px;
                font-weight: bold;
                color: #00d4aa;
                padding: 5px;
            }
        """)
        title_layout.addWidget(title_label)
        
        # 显示模式切换
        self.monitor_mode_combo = QComboBox()
        self.monitor_mode_combo.addItems(["活跃通道", "所有通道", "设备通道"])
        self.monitor_mode_combo.currentTextChanged.connect(self.update_channel_monitor)
        title_layout.addWidget(self.monitor_mode_combo)
        
        title_layout.addStretch()
        layout.addLayout(title_layout)
        
        # 通道监控区域
        scroll_area = QScrollArea()
        scroll_area.setMaximumHeight(150)
        scroll_area.setWidgetResizable(True)
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        
        self.monitor_container = QWidget()
        self.monitor_layout = QHBoxLayout(self.monitor_container)
        self.monitor_layout.setAlignment(Qt.AlignLeft)
        
        # 创建通道显示器
        self.channel_monitors = []
        for i in range(16):  # 显示前16个通道
            monitor = self.create_channel_monitor(i + 1)
            self.channel_monitors.append(monitor)
            self.monitor_layout.addWidget(monitor)
            
        scroll_area.setWidget(self.monitor_container)
        layout.addWidget(scroll_area)
        
        # 启动定时器更新通道监控
        self.monitor_timer = QTimer()
        self.monitor_timer.timeout.connect(self.update_channel_monitor)
        self.monitor_timer.start(100)  # 100ms刷新一次
        
        return panel
        
    def create_channel_monitor(self, channel: int) -> QWidget:
        """创建单个通道监控器"""
        monitor = QWidget()
        monitor.setFixedSize(60, 120)
        
        layout = QVBoxLayout(monitor)
        layout.setSpacing(2)
        
        # 通道号
        channel_label = QLabel(str(channel))
        channel_label.setAlignment(Qt.AlignCenter)
        channel_label.setStyleSheet("""
            QLabel {
                color: #00d4aa;
                font-size: 10px;
                font-weight: bold;
                background: rgba(0, 212, 170, 0.2);
                border-radius: 3px;
                padding: 2px;
            }
        """)
        layout.addWidget(channel_label)
        
        # 数值显示
        value_label = QLabel("0")
        value_label.setAlignment(Qt.AlignCenter)
        value_label.setStyleSheet("""
            QLabel {
                color: #ffffff;
                font-size: 12px;
                font-weight: bold;
                background: #2c3e50;
                border-radius: 4px;
                padding: 3px;
            }
        """)
        layout.addWidget(value_label)
        
        # 垂直进度条
        progress_bar = QProgressBar()
        progress_bar.setOrientation(Qt.Vertical)
        progress_bar.setRange(0, 255)
        progress_bar.setValue(0)
        progress_bar.setFixedSize(20, 70)
        progress_bar.setStyleSheet("""
            QProgressBar {
                border: 2px solid #34495e;
                border-radius: 8px;
                text-align: center;
                background: #2c3e50;
            }
            QProgressBar::chunk {
                background: qlineargradient(x1:0, y1:1, x2:0, y2:0,
                    stop:0 #e74c3c, stop:0.3 #f39c12, 
                    stop:0.6 #f1c40f, stop:1 #27ae60);
                border-radius: 6px;
            }
        """)
        
        layout.addWidget(progress_bar, alignment=Qt.AlignCenter)
        
        monitor.setStyleSheet("""
            QWidget {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 rgba(52, 73, 94, 0.8), stop:1 rgba(44, 62, 80, 0.8));
                border: 1px solid #34495e;
                border-radius: 8px;
                margin: 2px;
            }
        """)
        
        # 存储引用以便更新
        monitor.channel = channel
        monitor.value_label = value_label
        monitor.progress_bar = progress_bar
        
        return monitor
        
    def update_channel_monitor(self):
        """更新通道监控显示"""
        mode = self.monitor_mode_combo.currentText()
        
        if mode == "活跃通道":
            # 只显示值大于0的通道
            active_channels = []
            for i in range(1, 513):
                value = self.controller.get_channel(i)
                if value > 0:
                    active_channels.append((i, value))
            
            # 更新显示
            for i, monitor in enumerate(self.channel_monitors):
                if i < len(active_channels):
                    channel, value = active_channels[i]
                    monitor.channel = channel
                    monitor.value_label.setText(str(value))
                    monitor.progress_bar.setValue(value)
                    monitor.findChild(QLabel).setText(str(channel))
                    monitor.setVisible(True)
                else:
                    monitor.setVisible(False)
                    
        elif mode == "所有通道":
            # 显示前16个通道
            for i, monitor in enumerate(self.channel_monitors):
                channel = i + 1
                value = self.controller.get_channel(channel)
                monitor.value_label.setText(str(value))
                monitor.progress_bar.setValue(value)
                monitor.setVisible(True)
                
        elif mode == "设备通道":
            # 显示当前设备使用的通道
            device_channels = []
            for device in self.devices:
                for ch in range(device.start_channel, device.start_channel + device.channel_count):
                    if ch <= 512:
                        value = self.controller.get_channel(ch)
                        device_channels.append((ch, value))
            
            # 更新显示
            for i, monitor in enumerate(self.channel_monitors):
                if i < len(device_channels):
                    channel, value = device_channels[i]
                    monitor.channel = channel
                    monitor.value_label.setText(str(value))
                    monitor.progress_bar.setValue(value)
                    monitor.findChild(QLabel).setText(str(channel))
                    monitor.setVisible(True)
                else:
                    monitor.setVisible(False)
        
    def create_menu_bar(self):
        """创建菜单栏"""
        menubar = self.menuBar()
        
        # 文件菜单
        file_menu = menubar.addMenu('文件')
        
        new_action = QAction('新建项目', self)
        new_action.setShortcut('Ctrl+N')
        new_action.triggered.connect(self.new_project)
        file_menu.addAction(new_action)
        
        open_action = QAction('打开项目', self)
        open_action.setShortcut('Ctrl+O')
        open_action.triggered.connect(self.open_project)
        file_menu.addAction(open_action)
        
        save_action = QAction('保存项目', self)
        save_action.setShortcut('Ctrl+S')
        save_action.triggered.connect(self.save_project)
        file_menu.addAction(save_action)
        
        file_menu.addSeparator()
        
        exit_action = QAction('退出', self)
        exit_action.setShortcut('Ctrl+Q')
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)
        
        # 工具菜单
        tools_menu = menubar.addMenu('工具')
        
        rs485_monitor_action = QAction('🔗 RS485设备监控', self)
        rs485_monitor_action.triggered.connect(self.open_rs485_monitor)
        tools_menu.addAction(rs485_monitor_action)
        
        tools_menu.addSeparator()
        
        scan_devices_action = QAction('🔍 扫描RS485设备', self)
        scan_devices_action.triggered.connect(self.scan_rs485_devices)
        tools_menu.addAction(scan_devices_action)
        
        # 帮助菜单
        help_menu = menubar.addMenu('帮助')
        
        about_action = QAction('关于', self)
        about_action.triggered.connect(self.show_about)
        help_menu.addAction(about_action)
        
    def create_status_bar(self):
        """创建状态栏"""
        status_bar = self.statusBar()
        
        # DMX状态
        self.dmx_status_label = QLabel("DMX: 未连接")
        status_bar.addWidget(self.dmx_status_label)
        
        status_bar.addPermanentWidget(QLabel("DMX512专业灯光控制系统 v1.0"))
        
    def apply_styles(self):
        """应用炫酷界面样式"""
        self.setStyleSheet("""
            /* 主窗口背景 */
            QMainWindow {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1, 
                    stop:0 #1a1a2e, stop:0.5 #16213e, stop:1 #0f3460);
                color: #ffffff;
                font-family: 'Microsoft YaHei', 'Arial', sans-serif;
            }
            
            /* 中央窗口 */
            QWidget {
                background: transparent;
                color: #ffffff;
            }
            
            /* 群组框样式 */
            QGroupBox {
                font-weight: bold;
                font-size: 14px;
                border: 2px solid #00d4aa;
                border-radius: 12px;
                margin-top: 15px;
                padding-top: 15px;
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 rgba(0, 212, 170, 0.1), stop:1 rgba(0, 212, 170, 0.05));
                color: #00d4aa;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 15px;
                padding: 0 8px 0 8px;
                background: #1a1a2e;
                border-radius: 6px;
            }
            
            /* 炫酷按钮样式 */
            QPushButton {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #00d4aa, stop:1 #007991);
                border: none;
                color: white;
                padding: 12px 20px;
                text-align: center;
                font-size: 14px;
                font-weight: bold;
                border-radius: 8px;
                min-height: 20px;
            }
            QPushButton:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #00e6c2, stop:1 #008da8);
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(0, 212, 170, 0.4);
            }
            QPushButton:pressed {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #00b894, stop:1 #006b7d);
                transform: translateY(0px);
            }
            
            /* 特殊按钮样式 */
            QPushButton[objectName="danger"] {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #ff6b6b, stop:1 #d63031);
            }
            QPushButton[objectName="danger"]:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #ff7675, stop:1 #e17055);
            }
            
            QPushButton[objectName="warning"] {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #fdcb6e, stop:1 #f39c12);
            }
            QPushButton[objectName="warning"]:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #fedb8e, stop:1 #f5b041);
            }
            
            /* 现代化滑块样式 */
            QSlider::groove:horizontal {
                border: 1px solid #34495e;
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #2c3e50, stop:1 #34495e);
                height: 12px;
                border-radius: 6px;
            }
            QSlider::sub-page:horizontal {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                    stop:0 #00d4aa, stop:1 #00cec9);
                border: 1px solid #00d4aa;
                height: 12px;
                border-radius: 6px;
            }
            QSlider::handle:horizontal {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #ffffff, stop:1 #ecf0f1);
                border: 2px solid #00d4aa;
                width: 20px;
                height: 20px;
                margin-top: -6px;
                margin-bottom: -6px;
                border-radius: 12px;
            }
            QSlider::handle:horizontal:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #00e6c2, stop:1 #ffffff);
                box-shadow: 0 0 10px rgba(0, 212, 170, 0.8);
            }
            
            /* 垂直滑块样式 */
            QSlider::groove:vertical {
                border: 1px solid #34495e;
                background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                    stop:0 #2c3e50, stop:1 #34495e);
                width: 12px;
                border-radius: 6px;
            }
            QSlider::sub-page:vertical {
                background: qlineargradient(x1:0, y1:1, x2:0, y2:0,
                    stop:0 #00d4aa, stop:1 #00cec9);
                border: 1px solid #00d4aa;
                width: 12px;
                border-radius: 6px;
            }
            QSlider::handle:vertical {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                    stop:0 #ffffff, stop:1 #ecf0f1);
                border: 2px solid #00d4aa;
                width: 20px;
                height: 20px;
                margin-left: -6px;
                margin-right: -6px;
                border-radius: 12px;
            }
            QSlider::handle:vertical:hover {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                    stop:0 #00e6c2, stop:1 #ffffff);
                box-shadow: 0 0 10px rgba(0, 212, 170, 0.8);
            }
            
            /* 输入框样式 */
            QSpinBox, QComboBox, QLineEdit {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #34495e, stop:1 #2c3e50);
                border: 2px solid #00d4aa;
                border-radius: 8px;
                padding: 8px;
                color: #ffffff;
                font-size: 14px;
                min-height: 20px;
            }
            QSpinBox:focus, QComboBox:focus, QLineEdit:focus {
                border: 2px solid #00e6c2;
                box-shadow: 0 0 10px rgba(0, 212, 170, 0.5);
            }
            
            /* 下拉框箭头 */
            QComboBox::drop-down {
                border: none;
                background: #00d4aa;
                border-radius: 4px;
                width: 20px;
            }
            QComboBox::down-arrow {
                image: none;
                border-left: 5px solid transparent;
                border-right: 5px solid transparent;
                border-top: 5px solid white;
                margin: 5px;
            }
            
            /* 列表样式 */
            QListWidget {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #34495e, stop:1 #2c3e50);
                border: 2px solid #00d4aa;
                border-radius: 8px;
                padding: 5px;
                color: #ffffff;
                font-size: 14px;
            }
            QListWidget::item {
                background: transparent;
                border-radius: 4px;
                padding: 8px;
                margin: 2px 0;
            }
            QListWidget::item:hover {
                background: rgba(0, 212, 170, 0.2);
            }
            QListWidget::item:selected {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #00d4aa, stop:1 #00b894);
            }
            
            /* 标签样式 */
            QLabel {
                color: #ecf0f1;
                font-size: 14px;
            }
            
            /* 状态栏样式 */
            QStatusBar {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                    stop:0 #2c3e50, stop:1 #34495e);
                border-top: 2px solid #00d4aa;
                color: #ffffff;
                font-size: 12px;
            }
            
            /* 菜单栏样式 */
            QMenuBar {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #34495e, stop:1 #2c3e50);
                color: #ffffff;
                border-bottom: 2px solid #00d4aa;
            }
            QMenuBar::item {
                background: transparent;
                padding: 8px 16px;
            }
            QMenuBar::item:hover {
                background: rgba(0, 212, 170, 0.3);
                border-radius: 4px;
            }
            
            /* 菜单样式 */
            QMenu {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #34495e, stop:1 #2c3e50);
                border: 2px solid #00d4aa;
                border-radius: 8px;
                color: #ffffff;
            }
            QMenu::item {
                padding: 8px 20px;
                border-radius: 4px;
            }
            QMenu::item:hover {
                background: rgba(0, 212, 170, 0.3);
            }
            
            /* 滚动条样式 */
            QScrollBar:vertical {
                background: #2c3e50;
                width: 12px;
                border-radius: 6px;
            }
            QScrollBar::handle:vertical {
                background: #00d4aa;
                border-radius: 6px;
                min-height: 30px;
            }
            QScrollBar::handle:vertical:hover {
                background: #00e6c2;
            }
            
            /* 对话框样式 */
            QDialog {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1, 
                    stop:0 #1a1a2e, stop:0.5 #16213e, stop:1 #0f3460);
                color: #ffffff;
            }
        """)
        
    def init_dmx(self):
        """初始化DMX系统"""
        # 默认使用模拟接口
        sim_interface = SimulatedDMXInterface("模拟DMX接口")
        self.controller.set_interface(sim_interface)
        self.update_connection_status()
        
        # 添加一些示例设备
        self.add_example_devices()
        
    def add_example_devices(self):
        """添加示例设备"""
        # RGB灯
        rgb_light = RGBLight("RGB射灯1", 1)
        self.add_device_widget(rgb_light)
        
        # RGBW灯
        rgbw_light = RGBWLight("RGBW洗墙灯1", 4)
        self.add_device_widget(rgbw_light)
        
        # 摇头灯
        moving_head = MovingHead("摇头灯1", 8)
        self.add_device_widget(moving_head)
        
    def add_device_widget(self, device: DMXDevice):
        """添加设备控制组件"""
        device_widget = DeviceWidget(device, self.controller)
        self.device_layout.addWidget(device_widget)
        self.devices.append(device)
        
    def connect_dmx(self):
        """连接DMX接口"""
        interface_data = self.interface_combo.currentData()
        
        if interface_data == "simulator":
            interface = SimulatedDMXInterface("模拟DMX接口")
        elif interface_data.startswith("serial:"):
            port = interface_data.split(":", 1)[1]
            interface = SerialDMXInterface(port, name=f"串口DMX({port})")
        elif interface_data.startswith("rs485:"):
            port = interface_data.split(":", 1)[1]
            # 显示RS485配置对话框
            config_dialog = RS485ConfigDialog(port, self)
            if config_dialog.exec_() == QDialog.Accepted:
                config = config_dialog.get_config()
                interface = RS485DMXInterface(
                    port=port,
                    baudrate=config['baudrate'],
                    protocol=config['protocol'],
                    name=f"RS485-DMX({port})"
                )
            else:
                return
        else:
            QMessageBox.warning(self, "错误", "未知的接口类型")
            return
            
        if self.controller.set_interface(interface):
            self.connect_btn.setText("断开连接")
            self.connect_btn.clicked.disconnect()
            self.connect_btn.clicked.connect(self.disconnect_dmx)
            
            # 如果是RS485接口，显示设备扫描结果
            if isinstance(interface, RS485DMXInterface):
                self.show_rs485_devices(interface)
        else:
            QMessageBox.warning(self, "连接失败", "无法连接到DMX接口，请检查设备连接和配置")
            
        self.update_connection_status()
        
    def show_rs485_devices(self, interface: RS485DMXInterface):
        """显示RS485设备监控窗口"""
        devices = interface.get_device_list()
        
        if devices:
            # 显示设备列表
            device_list = "\n".join([f"• {device}" for device in devices])
            QMessageBox.information(
                self, "设备扫描完成", 
                f"发现 {len(devices)} 个RS485设备:\n\n{device_list}\n\n"
                "可以通过菜单栏打开设备监控窗口查看详细信息。"
            )
            
            # 自动打开设备监控窗口
            self.open_rs485_monitor()
        else:
            QMessageBox.information(
                self, "设备扫描完成", 
                "未发现任何RS485设备。\n\n"
                "请检查：\n"
                "• 设备电源和连接\n"
                "• RS485通信参数设置\n"
                "• 设备ID和波特率配置"
            )
    
    def open_rs485_monitor(self):
        """打开RS485设备监控窗口"""
        if isinstance(self.controller.interface, RS485DMXInterface):
            monitor = RS485DeviceMonitor(self.controller.interface, self)
            monitor.show()
        else:
            QMessageBox.warning(self, "错误", "当前未连接RS485接口")
    
    def scan_rs485_devices(self):
        """手动扫描RS485设备"""
        if isinstance(self.controller.interface, RS485DMXInterface):
            # 显示扫描进度对话框
            progress = QProgressDialog("正在扫描RS485设备...", "取消", 0, 100, self)
            progress.setWindowTitle("设备扫描")
            progress.setModal(True)
            progress.show()
            
            # 执行扫描
            QApplication.processEvents()
            progress.setValue(50)
            
            try:
                devices = self.controller.interface.scan_devices()
                progress.setValue(100)
                
                if devices:
                    device_list = "\n".join([f"• {device}" for device in devices])
                    QMessageBox.information(
                        self, "扫描完成", 
                        f"发现 {len(devices)} 个设备:\n\n{device_list}"
                    )
                else:
                    QMessageBox.information(
                        self, "扫描完成", 
                        "未发现任何设备。请检查设备连接和配置。"
                    )
            except Exception as e:
                QMessageBox.critical(self, "扫描失败", f"设备扫描时发生错误：{str(e)}")
            finally:
                progress.close()
        else:
            QMessageBox.warning(self, "错误", "当前未连接RS485接口")
        
    def disconnect_dmx(self):
        """断开DMX接口"""
        if self.controller.interface:
            self.controller.interface.disconnect()
        
        self.connect_btn.setText("连接")
        self.connect_btn.clicked.disconnect()
        self.connect_btn.clicked.connect(self.connect_dmx)
        self.update_connection_status()
        
    def update_connection_status(self):
        """更新连接状态显示"""
        if self.controller.interface and self.controller.interface.is_connected:
            self.status_indicator.setText("已连接")
            self.status_indicator.setStyleSheet("color: green; font-weight: bold;")
            self.dmx_status_label.setText(f"DMX: 已连接 ({self.controller.interface.name})")
        else:
            self.status_indicator.setText("未连接")
            self.status_indicator.setStyleSheet("color: red; font-weight: bold;")
            self.dmx_status_label.setText("DMX: 未连接")
            
    def on_master_dimmer_changed(self, value: int):
        """主亮度变化处理"""
        self.master_value_label.setText(f"{value}%")
        # 这里可以实现全局亮度控制逻辑
        
    def blackout_all(self):
        """全部熄灭"""
        self.controller.blackout()
        QMessageBox.information(self, "操作完成", "所有灯光已熄灭")
        
    def full_on_all(self):
        """全部点亮"""
        # 将所有通道设为最大值
        for i in range(1, 513):
            self.controller.set_channel(i, 255)
        QMessageBox.information(self, "操作完成", "所有通道已设为最大值")
        
    def test_channels(self):
        """通道测试"""
        reply = QMessageBox.question(
            self, "通道测试", 
            "这将依次点亮所有通道进行测试，是否继续？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.run_channel_test()
            
    def run_channel_test(self):
        """运行通道测试"""
        # 这里可以实现通道测试逻辑
        QMessageBox.information(self, "测试完成", "通道测试已完成")
        
    def add_device(self):
        """添加设备对话框"""
        dialog = AddDeviceDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            device_type, name, start_channel = dialog.get_device_info()
            
            if device_type == "RGB灯":
                device = RGBLight(name, start_channel)
            elif device_type == "RGBW灯":
                device = RGBWLight(name, start_channel)
            elif device_type == "摇头灯":
                device = MovingHead(name, start_channel)
            else:
                return
                
            self.add_device_widget(device)
            
    def remove_device(self):
        """删除选中的设备"""
        # 这里可以实现设备删除逻辑
        pass
        
    def save_scene(self):
        """保存当前场景"""
        name, ok = QInputDialog.getText(self, '保存场景', '请输入场景名称:')
        if ok and name:
            # 保存当前所有通道状态
            scene_data = {}
            for i in range(1, 513):
                value = self.controller.get_channel(i)
                if value > 0:
                    scene_data[i] = value
                    
            self.scenes[name] = scene_data
            self.update_scene_list()
            QMessageBox.information(self, "保存成功", f"场景 '{name}' 已保存")
            
    def load_scene(self, item):
        """加载选中的场景"""
        scene_name = item.text()
        if scene_name in self.scenes:
            # 清空所有通道
            self.controller.blackout()
            
            # 加载场景数据
            scene_data = self.scenes[scene_name]
            for channel, value in scene_data.items():
                self.controller.set_channel(channel, value)
                
            QMessageBox.information(self, "加载成功", f"场景 '{scene_name}' 已加载")
            
    def delete_scene(self):
        """删除选中的场景"""
        current_item = self.scene_list.currentItem()
        if current_item:
            scene_name = current_item.text()
            reply = QMessageBox.question(
                self, "删除场景", 
                f"确定要删除场景 '{scene_name}' 吗？",
                QMessageBox.Yes | QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                del self.scenes[scene_name]
                self.update_scene_list()
                QMessageBox.information(self, "删除成功", f"场景 '{scene_name}' 已删除")
                
    def update_scene_list(self):
        """更新场景列表"""
        self.scene_list.clear()
        for scene_name in self.scenes.keys():
            self.scene_list.addItem(scene_name)
            
    def new_project(self):
        """新建项目"""
        reply = QMessageBox.question(
            self, "新建项目", 
            "这将清空当前所有设置，是否继续？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 清空设备和场景
            self.devices.clear()
            self.scenes.clear()
            
            # 清空界面
            for i in reversed(range(self.device_layout.count())):
                self.device_layout.itemAt(i).widget().setParent(None)
                
            self.update_scene_list()
            self.controller.blackout()
            
    def open_project(self):
        """打开项目文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开项目", "", "DMX项目文件 (*.dmx);;所有文件 (*)"
        )
        
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    project_data = json.load(f)
                    
                # 加载项目数据
                self.load_project_data(project_data)
                QMessageBox.information(self, "打开成功", "项目文件已成功打开")
                
            except Exception as e:
                QMessageBox.critical(self, "打开失败", f"无法打开项目文件：{str(e)}")
                
    def save_project(self):
        """保存项目文件"""
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存项目", "", "DMX项目文件 (*.dmx);;所有文件 (*)"
        )
        
        if file_path:
            try:
                project_data = self.get_project_data()
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(project_data, f, indent=2, ensure_ascii=False)
                    
                QMessageBox.information(self, "保存成功", "项目文件已成功保存")
                
            except Exception as e:
                QMessageBox.critical(self, "保存失败", f"无法保存项目文件：{str(e)}")
                
    def get_project_data(self) -> dict:
        """获取项目数据"""
        return {
            "devices": [
                {
                    "type": device.__class__.__name__,
                    "name": device.name,
                    "start_channel": device.start_channel
                }
                for device in self.devices
            ],
            "scenes": self.scenes
        }
        
    def load_project_data(self, data: dict):
        """加载项目数据"""
        # 清空当前项目
        self.new_project()
        
        # 加载设备
        for device_data in data.get("devices", []):
            device_type = device_data["type"]
            name = device_data["name"]
            start_channel = device_data["start_channel"]
            
            if device_type == "RGBLight":
                device = RGBLight(name, start_channel)
            elif device_type == "RGBWLight":
                device = RGBWLight(name, start_channel)
            elif device_type == "MovingHead":
                device = MovingHead(name, start_channel)
            else:
                continue
                
            self.add_device_widget(device)
            
        # 加载场景
        self.scenes = data.get("scenes", {})
        self.update_scene_list()
        
    def show_about(self):
        """显示关于对话框"""
        QMessageBox.about(
            self, "关于DMX512控制系统",
            """
            <h3>DMX512专业灯光控制系统</h3>
            <p>版本: 1.0</p>
            <p>基于PyQt5开发的专业灯光控制软件</p>
            <p>支持多种DMX设备的颜色、亮度等参数控制</p>
            <br>
            <p>功能特性:</p>
            <ul>
            <li>🎨 颜色控制：RGB/RGBW颜色调节</li>
            <li>🔆 亮度控制：主控亮度和单通道亮度调节</li>
            <li>🎭 设备管理：支持多种DMX设备类型</li>
            <li>📋 场景预设：保存和调用场景配置</li>
            <li>🎯 实时预览：实时显示颜色和参数效果</li>
            <li>🔧 通道控制：精确的512通道DMX控制</li>
            </ul>
            """
        )
        
    def closeEvent(self, event):
        """程序关闭事件"""
        reply = QMessageBox.question(
            self, "退出程序", 
            "确定要退出DMX控制系统吗？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 清理资源
            if self.controller.interface:
                self.controller.interface.disconnect()
            event.accept()
        else:
            event.ignore()


class AddDeviceDialog(QDialog):
    """添加设备对话框"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.init_ui()
        
    def init_ui(self):
        self.setWindowTitle("添加DMX设备")
        self.setFixedSize(350, 300)
        
        layout = QVBoxLayout()
        layout.setSpacing(15)
        layout.setContentsMargins(20, 20, 20, 20)
        
        # 设备类型
        type_label = QLabel("设备类型:")
        type_label.setStyleSheet("font-weight: bold; font-size: 14px; color: #00d4aa;")
        layout.addWidget(type_label)
        
        self.device_type_combo = QComboBox()
        self.device_type_combo.addItems(["RGB灯", "RGBW灯", "摇头灯"])
        self.device_type_combo.setFixedHeight(35)
        self.device_type_combo.setStyleSheet("""
            QComboBox {
                padding: 8px;
                font-size: 13px;
                border: 2px solid #00d4aa;
                border-radius: 6px;
                background: white;
            }
        """)
        layout.addWidget(self.device_type_combo)
        
        # 设备名称
        name_label = QLabel("设备名称:")
        name_label.setStyleSheet("font-weight: bold; font-size: 14px; color: #00d4aa;")
        layout.addWidget(name_label)
        
        self.name_edit = QLineEdit()
        self.name_edit.setText("新设备")
        self.name_edit.setFixedHeight(35)
        self.name_edit.setPlaceholderText("请输入设备名称")
        self.name_edit.setStyleSheet("""
            QLineEdit {
                padding: 8px;
                font-size: 13px;
                border: 2px solid #00d4aa;
                border-radius: 6px;
                background: white;
            }
        """)
        layout.addWidget(self.name_edit)
        
        # 起始通道
        channel_label = QLabel("起始通道:")
        channel_label.setStyleSheet("font-weight: bold; font-size: 14px; color: #00d4aa;")
        layout.addWidget(channel_label)
        
        channel_layout = QHBoxLayout()
        self.channel_spinbox = QSpinBox()
        self.channel_spinbox.setRange(1, 512)
        self.channel_spinbox.setValue(1)
        self.channel_spinbox.setFixedHeight(35)
        self.channel_spinbox.setFixedWidth(120)
        self.channel_spinbox.setStyleSheet("""
            QSpinBox {
                padding: 8px;
                font-size: 13px;
                border: 2px solid #00d4aa;
                border-radius: 6px;
                background: white;
            }
        """)
        channel_layout.addWidget(self.channel_spinbox)
        
        channel_info = QLabel("(范围: 1-512)")
        channel_info.setStyleSheet("color: #666; font-size: 12px; margin-left: 10px;")
        channel_layout.addWidget(channel_info)
        channel_layout.addStretch()
        
        layout.addLayout(channel_layout)
        
        # 间距
        layout.addSpacing(20)
        
        # 按钮区域
        button_layout = QHBoxLayout()
        
        cancel_btn = QPushButton("取消")
        cancel_btn.setFixedSize(80, 35)
        cancel_btn.setStyleSheet("""
            QPushButton {
                background: #6c757d;
                color: white;
                border: none;
                border-radius: 6px;
                font-weight: bold;
            }
            QPushButton:hover {
                background: #5a6268;
            }
        """)
        cancel_btn.clicked.connect(self.reject)
        
        ok_btn = QPushButton("确定")
        ok_btn.setFixedSize(80, 35)
        ok_btn.setStyleSheet("""
            QPushButton {
                background: #00d4aa;
                color: white;
                border: none;
                border-radius: 6px;
                font-weight: bold;
            }
            QPushButton:hover {
                background: #00b894;
            }
        """)
        ok_btn.clicked.connect(self.accept)
        
        button_layout.addStretch()
        button_layout.addWidget(cancel_btn)
        button_layout.addSpacing(10)
        button_layout.addWidget(ok_btn)
        
        layout.addLayout(button_layout)
        self.setLayout(layout)
        
    def get_device_info(self) -> Tuple[str, str, int]:
        """获取设备信息"""
        return (
            self.device_type_combo.currentText(),
            self.name_edit.text(),
            self.channel_spinbox.value()
        )


class RS485ConfigDialog(QDialog):
    """RS485配置对话框"""
    
    def __init__(self, port: str, parent=None):
        super().__init__(parent)
        self.port = port
        self.init_ui()
        
    def init_ui(self):
        self.setWindowTitle(f"RS485配置 - {self.port}")
        self.setFixedSize(500, 650)
        
        layout = QVBoxLayout()
        layout.setSpacing(15)  # 增加组件间距
        layout.setContentsMargins(20, 20, 20, 20)  # 增加边距
        
        # 端口信息
        port_group = QGroupBox("📡 端口信息")
        port_layout = QVBoxLayout()
        port_layout.setSpacing(8)
        port_layout.setContentsMargins(15, 15, 15, 15)
        
        port_info_label = QLabel(f"端口: {self.port}")
        port_info_label.setStyleSheet("font-size: 14px; font-weight: bold; color: #00d4aa;")
        port_layout.addWidget(port_info_label)
        
        port_group.setLayout(port_layout)
        layout.addWidget(port_group)
        
        # 通信设置
        comm_group = QGroupBox("⚙️ 通信设置")
        comm_layout = QGridLayout()
        comm_layout.setSpacing(12)
        comm_layout.setContentsMargins(15, 15, 15, 15)
        
        # 波特率
        baudrate_label = QLabel("波特率:")
        baudrate_label.setStyleSheet("font-weight: bold;")
        comm_layout.addWidget(baudrate_label, 0, 0)
        self.baudrate_combo = QComboBox()
        self.baudrate_combo.addItems(["9600", "19200", "38400", "57600", "115200", "230400"])
        self.baudrate_combo.setCurrentText("115200")
        self.baudrate_combo.setMinimumHeight(30)
        comm_layout.addWidget(self.baudrate_combo, 0, 1)
        
        # 数据位
        databits_label = QLabel("数据位:")
        databits_label.setStyleSheet("font-weight: bold;")
        comm_layout.addWidget(databits_label, 1, 0)
        self.databits_combo = QComboBox()
        self.databits_combo.addItems(["7", "8"])
        self.databits_combo.setCurrentText("8")
        self.databits_combo.setMinimumHeight(30)
        comm_layout.addWidget(self.databits_combo, 1, 1)
        
        # 停止位
        stopbits_label = QLabel("停止位:")
        stopbits_label.setStyleSheet("font-weight: bold;")
        comm_layout.addWidget(stopbits_label, 2, 0)
        self.stopbits_combo = QComboBox()
        self.stopbits_combo.addItems(["1", "2"])
        self.stopbits_combo.setMinimumHeight(30)
        comm_layout.addWidget(self.stopbits_combo, 2, 1)
        
        # 校验位
        parity_label = QLabel("校验位:")
        parity_label.setStyleSheet("font-weight: bold;")
        comm_layout.addWidget(parity_label, 3, 0)
        self.parity_combo = QComboBox()
        self.parity_combo.addItems(["无", "偶校验", "奇校验"])
        self.parity_combo.setMinimumHeight(30)
        comm_layout.addWidget(self.parity_combo, 3, 1)
        
        comm_group.setLayout(comm_layout)
        layout.addWidget(comm_group)
        
        # 协议设置
        protocol_group = QGroupBox("🔗 协议设置")
        protocol_layout = QVBoxLayout()
        protocol_layout.setSpacing(10)
        protocol_layout.setContentsMargins(15, 15, 15, 15)
        
        # 协议选择
        protocol_select_layout = QHBoxLayout()
        protocol_label = QLabel("协议类型:")
        protocol_label.setStyleSheet("font-weight: bold;")
        protocol_select_layout.addWidget(protocol_label)
        
        self.protocol_combo = QComboBox()
        self.protocol_combo.addItem("标准DMX512", RS485ProtocolType.STANDARD_DMX)
        self.protocol_combo.addItem("Modbus RTU", RS485ProtocolType.MODBUS_RTU)
        self.protocol_combo.addItem("自定义协议", RS485ProtocolType.CUSTOM_PROTOCOL)
        self.protocol_combo.setMinimumHeight(35)
        protocol_select_layout.addWidget(self.protocol_combo)
        protocol_layout.addLayout(protocol_select_layout)
        
        # 协议说明
        protocol_info = QLabel("""
        <b>协议说明:</b><br>
        📡 <b>标准DMX512:</b> 适用于标准DMX转RS485设备<br>
        🏭 <b>Modbus RTU:</b> 适用于支持Modbus的智能灯具<br>
        🔧 <b>自定义协议:</b> 适用于特殊定制设备
        """)
        protocol_info.setWordWrap(True)
        protocol_info.setStyleSheet("""
            QLabel {
                background: rgba(0, 212, 170, 0.1);
                border: 1px solid #00d4aa;
                border-radius: 8px;
                padding: 10px;
                font-size: 12px;
            }
        """)
        protocol_layout.addWidget(protocol_info)
        
        protocol_group.setLayout(protocol_layout)
        layout.addWidget(protocol_group)
        
        # 高级设置
        advanced_group = QGroupBox("🔧 高级设置")
        advanced_layout = QGridLayout()
        advanced_layout.setSpacing(12)
        advanced_layout.setContentsMargins(15, 15, 15, 15)
        
        # 设备扫描范围
        scan_range_label = QLabel("设备ID范围:")
        scan_range_label.setStyleSheet("font-weight: bold;")
        advanced_layout.addWidget(scan_range_label, 0, 0)
        
        scan_layout = QHBoxLayout()
        scan_layout.setSpacing(8)
        self.scan_start_spinbox = QSpinBox()
        self.scan_start_spinbox.setRange(1, 247)
        self.scan_start_spinbox.setValue(1)
        self.scan_start_spinbox.setMinimumHeight(30)
        self.scan_start_spinbox.setMinimumWidth(60)
        scan_layout.addWidget(self.scan_start_spinbox)
        
        to_label = QLabel("到")
        to_label.setAlignment(Qt.AlignCenter)
        scan_layout.addWidget(to_label)
        
        self.scan_end_spinbox = QSpinBox()
        self.scan_end_spinbox.setRange(1, 247)
        self.scan_end_spinbox.setValue(32)
        self.scan_end_spinbox.setMinimumHeight(30)
        self.scan_end_spinbox.setMinimumWidth(60)
        scan_layout.addWidget(self.scan_end_spinbox)
        scan_layout.addStretch()
        
        advanced_layout.addLayout(scan_layout, 0, 1)
        
        # 响应超时
        timeout_label = QLabel("响应超时:")
        timeout_label.setStyleSheet("font-weight: bold;")
        advanced_layout.addWidget(timeout_label, 1, 0)
        self.timeout_spinbox = QSpinBox()
        self.timeout_spinbox.setRange(50, 5000)
        self.timeout_spinbox.setValue(100)
        self.timeout_spinbox.setSuffix(" ms")
        self.timeout_spinbox.setMinimumHeight(30)
        self.timeout_spinbox.setMinimumWidth(120)
        advanced_layout.addWidget(self.timeout_spinbox, 1, 1)
        
        advanced_group.setLayout(advanced_layout)
        layout.addWidget(advanced_group)
        
        # 按钮区域
        layout.addStretch()  # 添加弹性空间，将按钮推到底部
        
        button_layout = QHBoxLayout()
        button_layout.setSpacing(10)
        button_layout.setContentsMargins(0, 15, 0, 0)
        
        test_btn = QPushButton("🔧 测试连接")
        test_btn.setMinimumHeight(40)
        test_btn.setMinimumWidth(120)
        test_btn.setStyleSheet("""
            QPushButton {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #fdcb6e, stop:1 #f39c12);
                border: none;
                color: white;
                font-size: 14px;
                font-weight: bold;
                border-radius: 8px;
            }
            QPushButton:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #fedb8e, stop:1 #f5b041);
            }
        """)
        test_btn.clicked.connect(self.test_connection)
        button_layout.addWidget(test_btn)
        
        button_layout.addStretch()
        
        ok_btn = QPushButton("✅ 确定")
        ok_btn.setMinimumHeight(40)
        ok_btn.setMinimumWidth(100)
        ok_btn.clicked.connect(self.accept)
        button_layout.addWidget(ok_btn)
        
        cancel_btn = QPushButton("❌ 取消")
        cancel_btn.setMinimumHeight(40)
        cancel_btn.setMinimumWidth(100)
        cancel_btn.setObjectName("danger")
        cancel_btn.clicked.connect(self.reject)
        button_layout.addWidget(cancel_btn)
        
        layout.addLayout(button_layout)
        self.setLayout(layout)
        
    def test_connection(self):
        """测试RS485连接"""
        try:
            config = self.get_config()
            
            # 创建临时接口进行测试
            test_interface = RS485DMXInterface(
                port=self.port,
                baudrate=config['baudrate'],
                protocol=config['protocol'],
                name="测试接口"
            )
            
            if test_interface.connect():
                QMessageBox.information(self, "测试成功", "RS485连接测试成功！")
                test_interface.disconnect()
            else:
                QMessageBox.warning(self, "测试失败", "RS485连接测试失败，请检查端口和设置")
                
        except Exception as e:
            QMessageBox.critical(self, "测试错误", f"连接测试时发生错误：{str(e)}")
            
    def get_config(self) -> dict:
        """获取配置"""
        return {
            'baudrate': int(self.baudrate_combo.currentText()),
            'databits': int(self.databits_combo.currentText()),
            'stopbits': int(self.stopbits_combo.currentText()),
            'parity': self.parity_combo.currentText(),
            'protocol': self.protocol_combo.currentData(),
            'scan_range': (self.scan_start_spinbox.value(), self.scan_end_spinbox.value()),
            'timeout': self.timeout_spinbox.value()
        }


class RS485DeviceMonitor(QDialog):
    """RS485设备监控对话框"""
    
    def __init__(self, interface: RS485DMXInterface, parent=None):
        super().__init__(parent)
        self.interface = interface
        self.device_widgets = {}
        self.init_ui()
        self.start_monitoring()
        
    def init_ui(self):
        self.setWindowTitle("🔗 RS485设备监控")
        self.setGeometry(200, 200, 1000, 700)
        self.setMinimumSize(800, 600)
        
        layout = QVBoxLayout()
        layout.setSpacing(15)
        layout.setContentsMargins(20, 20, 20, 20)
        
        # 标题栏
        title_layout = QHBoxLayout()
        title_label = QLabel("🔗 RS485设备实时监控")
        title_label.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                color: #00d4aa;
                padding: 10px;
            }
        """)
        title_layout.addWidget(title_label)
        title_layout.addStretch()
        layout.addLayout(title_layout)
        
        # 工具栏
        toolbar_layout = QHBoxLayout()
        toolbar_layout.setSpacing(10)
        
        refresh_btn = QPushButton("🔄 刷新设备")
        refresh_btn.setMinimumHeight(35)
        refresh_btn.setMinimumWidth(120)
        refresh_btn.clicked.connect(self.refresh_devices)
        toolbar_layout.addWidget(refresh_btn)
        
        stats_btn = QPushButton("📊 通信统计")
        stats_btn.setMinimumHeight(35)
        stats_btn.setMinimumWidth(120)
        stats_btn.clicked.connect(self.show_stats)
        toolbar_layout.addWidget(stats_btn)
        
        # 添加状态指示器
        self.status_label = QLabel("🟢 监控中...")
        self.status_label.setStyleSheet("""
            QLabel {
                background: rgba(0, 212, 170, 0.1);
                border: 1px solid #00d4aa;
                border-radius: 6px;
                padding: 8px 12px;
                font-weight: bold;
            }
        """)
        toolbar_layout.addWidget(self.status_label)
        
        toolbar_layout.addStretch()
        
        close_btn = QPushButton("❌ 关闭")
        close_btn.setMinimumHeight(35)
        close_btn.setMinimumWidth(100)
        close_btn.setObjectName("danger")
        close_btn.clicked.connect(self.close)
        toolbar_layout.addWidget(close_btn)
        
        layout.addLayout(toolbar_layout)
        
        # 设备列表
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        
        self.device_container = QWidget()
        self.device_layout = QVBoxLayout(self.device_container)
        self.device_layout.setAlignment(Qt.AlignTop)
        
        scroll_area.setWidget(self.device_container)
        layout.addWidget(scroll_area)
        
        self.setLayout(layout)
        self.refresh_devices()
        
    def refresh_devices(self):
        """刷新设备列表"""
        # 清空现有显示
        for widget in self.device_widgets.values():
            widget.setParent(None)
        self.device_widgets.clear()
        
        # 获取设备列表
        devices = self.interface.get_device_list()
        
        for device in devices:
            widget = self.create_device_widget(device)
            self.device_widgets[device.device_id] = widget
            self.device_layout.addWidget(widget)
            
    def create_device_widget(self, device: RS485Device) -> QWidget:
        """创建设备显示组件"""
        widget = QWidget()
        widget.setStyleSheet("""
            QWidget {
                border: 2px solid #00d4aa;
                border-radius: 10px;
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 rgba(0, 212, 170, 0.1), stop:1 rgba(0, 212, 170, 0.05));
                margin: 5px;
                padding: 10px;
            }
        """)
        
        layout = QVBoxLayout(widget)
        
        # 设备基本信息
        info_layout = QHBoxLayout()
        
        # 设备图标和名称
        icon_map = {
            RS485DeviceType.DMX_CONVERTER: "🔄",
            RS485DeviceType.INTELLIGENT_LIGHT: "💡",
            RS485DeviceType.DIMMER_PACK: "🎛️",
            RS485DeviceType.MOTOR_CONTROLLER: "⚙️"
        }
        icon = icon_map.get(device.device_type, "📦")
        
        name_label = QLabel(f"{icon} {device.name}")
        name_label.setStyleSheet("font-weight: bold; font-size: 16px; color: #00d4aa;")
        info_layout.addWidget(name_label)
        
        # 在线状态
        status_label = QLabel("🟢 在线" if device.is_online else "🔴 离线")
        status_label.setStyleSheet("font-size: 14px;")
        info_layout.addWidget(status_label)
        
        info_layout.addStretch()
        layout.addLayout(info_layout)
        
        # 设备详细信息
        details_layout = QGridLayout()
        
        details_layout.addWidget(QLabel("设备ID:"), 0, 0)
        details_layout.addWidget(QLabel(str(device.device_id)), 0, 1)
        
        details_layout.addWidget(QLabel("设备类型:"), 0, 2)
        details_layout.addWidget(QLabel(device.device_type.value), 0, 3)
        
        details_layout.addWidget(QLabel("起始地址:"), 1, 0)
        details_layout.addWidget(QLabel(str(device.start_address)), 1, 1)
        
        details_layout.addWidget(QLabel("通道数量:"), 1, 2)
        details_layout.addWidget(QLabel(str(device.channel_count)), 1, 3)
        
        if device.firmware_version:
            details_layout.addWidget(QLabel("固件版本:"), 2, 0)
            details_layout.addWidget(QLabel(device.firmware_version), 2, 1)
            
        if device.last_response_time > 0:
            import datetime
            last_time = datetime.datetime.fromtimestamp(device.last_response_time)
            details_layout.addWidget(QLabel("最后响应:"), 2, 2)
            details_layout.addWidget(QLabel(last_time.strftime("%H:%M:%S")), 2, 3)
            
        layout.addLayout(details_layout)
        
        # 设备状态数据
        if device.status_data:
            status_group = QGroupBox("设备状态")
            status_layout = QGridLayout()
            
            row = 0
            for key, value in device.status_data.items():
                status_layout.addWidget(QLabel(f"{key}:"), row, 0)
                status_layout.addWidget(QLabel(str(value)), row, 1)
                row += 1
                
            status_group.setLayout(status_layout)
            layout.addWidget(status_group)
            
        # 存储设备引用以便更新
        widget.device = device
        widget.status_label = status_label
        
        return widget
        
    def start_monitoring(self):
        """开始监控"""
        self.monitor_timer = QTimer()
        self.monitor_timer.timeout.connect(self.update_device_status)
        self.monitor_timer.start(1000)  # 1秒更新一次
        
    def update_device_status(self):
        """更新设备状态显示"""
        for device_id, widget in self.device_widgets.items():
            device = widget.device
            
            # 更新在线状态
            status_text = "🟢 在线" if device.is_online else "🔴 离线"
            widget.status_label.setText(status_text)
            
    def show_stats(self):
        """显示通信统计"""
        stats = self.interface.get_stats()
        
        stats_text = f"""
        <h3>通信统计信息</h3>
        <p><b>发送数据包:</b> {stats['packets_sent']}</p>
        <p><b>接收数据包:</b> {stats['packets_received']}</p>
        <p><b>错误次数:</b> {stats['errors']}</p>
        <p><b>最后错误:</b> {stats['last_error'] or '无'}</p>
        """
        
        QMessageBox.information(self, "通信统计", stats_text)
        
    def closeEvent(self, event):
        """关闭事件"""
        if hasattr(self, 'monitor_timer'):
            self.monitor_timer.stop()
        event.accept()


def main():
    """主函数"""
    app = QApplication(sys.argv)
    app.setApplicationName("DMX512控制系统")
    app.setApplicationVersion("1.0")
    
    # 设置应用图标
    app.setWindowIcon(app.style().standardIcon(QStyle.SP_ComputerIcon))
    
    # 创建主窗口
    window = DMXControllerGUI()
    window.show()
    
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
